 function C_callbackArduinoIn(obj,event,ID)
% CALLBACK FOR ARDUINO, PROCESSES THE PacketS THAT HAVE ARRIVED 
% AND CALLS THE PARADIGM TO PROCESS THE EVENTS

global CG Verbose; 
if isempty(CG.Sessions) return; end
ModuleType = 'Arduino';
ModuleName = CG.Sessions.Arduino(ID).Name;

%% CHECK FOR AVAILABLE DATA
BytesAvailable = get(CG.Sessions.Arduino(ID).S,'BytesAvailable');
BytesPerPacket = CG.Parameters.Arduino.BytesPerPacket;

%% MOVE DATA TO INTERNAL VARIABLE
if BytesAvailable>2*BytesPerPacket
  CG.Sessions.Arduino(ID).Iteration = CG.Sessions.Arduino(ID).Iteration + 1; % defined in the C_initialize
  ReadTime=now*CG.Misc.DateNum2SecFactor;
  CG.Sessions.Arduino(ID).ReadTimes(CG.Sessions.Arduino(ID).Iteration) = ReadTime;
  NewData = fread(CG.Sessions.Arduino(ID).S,BytesAvailable,'uint8');
  C_Logger('C_callbackArduinoIn',['Getting Data [ ',num2str(length(NewData)),' Packets]\n']);

  % IF WE ARE AT THE FIRST ROUND OF DATA ACQUISITION
  % GET THE START OF THE FIRST PACKET
  EndInts = CG.Parameters.Arduino.StopCharAsInt;
  if CG.Sessions.Arduino(ID).Iteration==1
    for StartPos=1:length(NewData)-1
      if NewData([StartPos:StartPos+1]) == EndInts;  break;  end
    end
    StartPos = StartPos + 2;
  else
    StartPos = 1;
  end

  % FIND LAST END OF PACKET
  NNewPackets = NaN;
  for StopPos=length(NewData):-1:2
    if sum(NewData([StopPos-1:StopPos]) == EndInts)==2;
      CurrentData = [CG.Data.Arduino(ID).UnfinishedPacket;NewData(StartPos:StopPos)];
      NNewPackets = length(CurrentData)/BytesPerPacket;
      if mod(NNewPackets,1) == 0; break; 
      else  % If not, search continues
        C_Logger('C_callbackArduino','Length of Data between Stops does not divide the Message Length\n');
      end
    end
  end
 
  if isnan(NNewPackets) | NNewPackets ==0 | mod(NNewPackets,1)>0
    keyboard;
  end
  
  
  % ASSIGN NUMBERS AND  NEW OLD PACKET
  OldPacketsAcquired = CG.Sessions.Arduino(ID).PacketsAcquired;
  CG.Sessions.Arduino(ID).PacketsAcquired = ...
    CG.Sessions.Arduino(ID).PacketsAcquired + NNewPackets;
  PacketsAcquired = CG.Sessions.Arduino(ID).PacketsAcquired;
  CG.Data.Arduino(ID).UnfinishedPacket = NewData(StopPos+1:end);
  
  % ENLARGE VARIABLES IN BIG STEPS (IF NECESSARY)
  if CG.Sessions.Arduino(ID).CurrentSize < PacketsAcquired
    NewSize = CG.Sessions.Arduino(ID).CurrentSize + CG.Parameters.Arduino.StepSize;
    CG.Data.Arduino(ID).Analog(NewSize,:) = 0; % EnlargeArray
    CG.Data.Arduino(ID).Digital(NewSize,:) = 0; % EnlargeArray
    CG.Data.Arduino(ID).Time(NewSize,:) = 0; % EnlargeArray
    CG.Sessions.Arduino(ID).CurrentSize = NewSize;
  end
  
  % TRANSFER PACKETS TO INTERNAL VARIABLES
  NAnalog = CG.Sessions.Arduino(ID).NAnalog;
  cInd = [OldPacketsAcquired+1 : PacketsAcquired];
  cPackets = reshape(CurrentData,BytesPerPacket,NNewPackets)';
  CG.Data.Arduino(ID).Analog(cInd,1:NAnalog)    =  cPackets(:,1:NAnalog)/255*CG.Parameters.Arduino.AnalogRange(2);
  CG.Data.Arduino(ID).Digital(cInd,1)        =  cPackets(:,NAnalog+1);
  DeltaTime = double(cPackets(:,CG.Parameters.Arduino.TimeInd));
  DeltaTime = [DeltaTime(:,1) + DeltaTime(:,2)/100]; % ms based time, ranging up to 254ms, at 10us res.
  CSDeltaTime = cumsum(DeltaTime)/1000; % convert to seconds
  CG.Data.Arduino(ID).Time(cInd,1) = CG.Sessions.Arduino(ID).LastTime + CSDeltaTime; % Time on Arduino since start
  CG.Data.Arduino(ID).Time(cInd,2) = ReadTime + CSDeltaTime - CSDeltaTime(end); % Computer time

  CG.Sessions.Arduino(ID).PacketsThisIteration = NNewPackets;
  CG.Sessions.Arduino(ID).TimeThisIteration = CSDeltaTime(end);

  
  CG.Sessions.Arduino(ID).LastTime = CG.Data.Arduino(ID).Time(cInd(end),1);
  CG.Data.Arduino(ID).UnfinishedPacket=NewData(StopPos+1:end);
  CG.Sessions.Arduino(ID).BusyState = bitget(CG.Data.Arduino(ID).Digital(cInd(end),1),8);
  
  %% DETECT EVENTS
  Events = struct('Name',{},'Data',{},'Time',{});
  
  % CHECK FOR STATE CHANGES ON THE DIGITAL CHANNELS
  if CG.Sessions.Arduino(ID).Iteration == 1
    cDigitalByte = [0;CG.Data.Arduino(ID).Digital(cInd,:)];
  else
    cDigitalByte = CG.Data.Arduino(ID).Digital([cInd(1)-1,cInd],:);
  end
  
  cDigital = zeros(size(cDigitalByte,1),CG.Sessions.Arduino(ID).NDigital);
  for iD=1:CG.Sessions.Arduino(ID).NDigital cDigital(:,iD) = bitget(cDigitalByte,iD); end
  cDiffDigital = diff(cDigital,1,1);
  [iT,iD] = find(cDiffDigital);
  for iE = 1:length(iD)
    Events(iE).Data = iD(iE); % Channel Number
    Events(iE).Time = CG.Data.Arduino(ID).Time(cInd(iT(iE)),2); % Event Time
    if cDiffDigital(iT(iE),iD(iE))>0;     Events(iE).Name = 'DI_to_High';
    else                                         Events(iE).Name = 'DI_to_Low';
    end
  end
  LastEvent = length(Events);
  
  % CHECK FOR STATE CHANGES ON THE ANALOG CHANNELS
  ThreshCh = ~isnan(CG.Sessions.Arduino(ID).AnalogThresholds);
  if any(ThreshCh)
    NThreshCh = sum(ThreshCh);
    if CG.Sessions.Arduino(ID).Iteration == 1
      cAnalog = [zeros(1,NThreshCh);CG.Data.Arduino(ID).Analog(cInd,ThreshCh)];
    else
      cAnalog = CG.Data.Arduino(ID).Analog([cInd(1)-1,cInd],ThreshCh);
    end
    
    Thresholds = CG.Sessions.Arduino(ID).AnalogThresholds(ThreshCh);
    cAnalog = bsxfun(@gt,cAnalog,Thresholds);
    ThreshChNums = find(ThreshCh);
    cDiffAnalog = diff(cAnalog,1,1);
    [iT,iD] = find(cDiffAnalog);
    for iE = 1:length(iD)
      Events(LastEvent + iE).Data = ThreshChNums(iD(iE)); % Channel Number
      Events(LastEvent + iE).Time = CG.Data.Arduino(ID).Time(cInd(iT(iE)),2); % Event Time
      if cDiffAnalog(iT(iE),iD(iE))>0;     Events(LastEvent + iE).Name = 'AI_to_High';
      else                                          Events(LastEvent + iE).Name = 'AI_to_Low';
      end
    end
    % FILTER OUT PAIRS OF SUPERSHORT UP-DOWN EVENTS
    EventDurations = diff(iT);
    cInd = find(EventDurations<20); % 2ms
    DeleteInd = [];
    for iE=1:length(cInd)
      if (Events(cInd(iE)).Data == Events(cInd(iE)+1).Data)
        DeleteInd(end+1:end+2) = [cInd(iE),cInd(iE)+1];
        %disp(['Filtered out Channel : ',n2s(Events(cInd(iE)).Data)]);
      end
    end
    if ~isempty(DeleteInd)
      SelInd = setdiff([1:length(iD)],DeleteInd);
      Events = Events(SelInd);
    end
  end
  
  if ~isempty(Events)
    % PROCESS EVENTS
    for iE=1:length(Events)
      CG.Paradigm.processEvent(ModuleName,Events(iE));
    end

    % RECORD TIMING AND EVENTS
    C_addEvents(ModuleType,ID,Events);
  end
      
  %% UPDATE ARDUINO DISPLAY
  if CG.Display.Arduino(ID).State C_updateArduinoDisplay(ID); end
end
